home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / DiskFileOutput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  26.6 KB  |  873 lines  |  [TEXT/KAHL]

  1. /* DiskFileOutput.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "DiskFileOutput.h"
  31. #include "Files.h"
  32. #include "Memory.h"
  33. #include "Alert.h"
  34. #include "ExecuteSynthesis.h"
  35. #include "ClipWarnDialog.h"
  36. #include "SynthProgressWindow.h"
  37. #include "BufferedFileOutput.h"
  38. #include "ErrorDaemon.h"
  39.  
  40.  
  41. #define CANCELCHECKTIMER (50)
  42.  
  43.  
  44. typedef struct
  45.     {
  46.         MyBoolean                            UseStereo;
  47.         long                                    SamplingRate;
  48.         OutputNumBitsType            NumBitsOut;
  49.         FileType*                            OutputFile;
  50.  
  51.         long                                    TotalSampleCount;
  52.         long                                    ClippedSampleCount;
  53.         largefixedsigned            MaxClipExtent;
  54.  
  55.         long                                    CancelCheck;
  56.  
  57.         SynthWinRec*                    Window;
  58.     } StateRecord;
  59.  
  60.  
  61. /* AIFF/AIFF-C File Format: */
  62. /*     "FORM" */
  63. /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  64. /*     4-byte type */
  65. /*        "AIFF" = AIFF format file */
  66. /*        "AIFC" = AIFF-C format file */
  67. /* in any order, these chunks can occur: */
  68. /*   Version Chunk (this only occurs in AIFF-C files) */
  69. /*     "FVER" */
  70. /*     4-byte big endian length, which should always be the value 4 (four) */
  71. /*     4-byte date code.  this is probably 0xA2805140 (stored big endian), but it */
  72. /*          probably doesn't matter. */
  73. /*   Common Chunk for AIFF files */
  74. /*     "COMM" */
  75. /*     4-byte big endian length. */
  76. /*        always 18 for AIFF files */
  77. /*     2-byte big endian number of channels */
  78. /*     4-byte big endian number of sample frames */
  79. /*     2-byte big endian number of bits per sample */
  80. /*        a value in the domain 1..32 */
  81. /*     10-byte extended precision number of frames per second */
  82. /*   Common Chunk for AIFF-C files */
  83. /*     "COMM" */
  84. /*     4-byte big endian length. */
  85. /*        22 + compression method string length for AIFF-C files */
  86. /*     2-byte big endian number of channels */
  87. /*     4-byte big endian number of sample frames */
  88. /*     2-byte big endian number of bits per sample */
  89. /*        a value in the domain 1..32 */
  90. /*     10-byte extended precision number of frames per second */
  91. /*     4-byte character code ID for the compression method */
  92. /*        "NONE" means there is no compression method used */
  93. /*     some characters in a string identifying the compression method */
  94. /*        this must be padded to an even number of bytes, but the pad is */
  95. /*        NOT included in the length descriptor for the chunk. */
  96. /*        for uncompressed data, the string should be */
  97. /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  98. /*        the total chunk length is thus 38 bytes. */
  99. /*   Sound Data Chunk */
  100. /*     "SSND" */
  101. /*     4-byte big endian number of bytes in sample data array */
  102. /*     4-byte big endian offset to the first byte of sample data in the array */
  103. /*     4-byte big endian number of bytes to which the sound data is aligned. */
  104. /*     any length vector of raw sound data. */
  105. /*        this must be padded to an even number of bytes, but the pad is */
  106. /*        NOT included in the length descriptor for the chunk. */
  107. /*        Samples are stored in an integral number of bytes, the smallest that */
  108. /*        is required for the specified number of bits.  If this is not an even */
  109. /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  110. /*        Multichannel sound is interleaved with the left channel first. */
  111. static MyBoolean            SetUpAIFFHeader(FileType* OutputFile, StateRecord* Info)
  112.     {
  113.         BufferedOutputRec*    Output;
  114.         unsigned long                Mantissa;
  115.         unsigned long                Exponent;
  116.         char                                StupidExtendedThing[10];
  117.  
  118.         Output = NewBufferedOutput(OutputFile);
  119.         if (Output == NIL)
  120.             {
  121.              FailurePoint1:
  122.                 return False;
  123.             }
  124.  
  125.         /* 0..3 */
  126.         /*     "FORM" */
  127.         if (!WriteBufferedOutput(Output,4,"FORM"))
  128.             {
  129.              FailurePoint2:
  130.                 EndBufferedOutput(Output);
  131.                 goto FailurePoint1;
  132.             }
  133.  
  134.         /* 4..7 */
  135.         /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  136.         if (!WriteBufferedUnsignedLongBigEndian(Output,0)) /* RESOLVED LATER */
  137.             {
  138.                 goto FailurePoint2;
  139.             }
  140.  
  141.         /* 8..11 */
  142.         /*     4-byte type */
  143.         /*        "AIFC" = AIFF-C format file */
  144.         if (!WriteBufferedOutput(Output,4,"AIFC"))
  145.             {
  146.                 goto FailurePoint2;
  147.             }
  148.  
  149.         /* 12..15 */
  150.         /*     "FVER" */
  151.         if (!WriteBufferedOutput(Output,4,"FVER"))
  152.             {
  153.                 goto FailurePoint2;
  154.             }
  155.  
  156.         /* 16..19 */
  157.         /*     4-byte big endian length, which should always be the value 4 (four) */
  158.         if (!WriteBufferedUnsignedLongBigEndian(Output,4))
  159.             {
  160.                 goto FailurePoint2;
  161.             }
  162.  
  163.         /* 20..23 */
  164.         /*     4-byte date code.  this is probably 0xA2805140 (stored big endian), but it */
  165.         /*          probably doesn't matter. */
  166.         if (!WriteBufferedUnsignedLongBigEndian(Output,0xA2805140))
  167.             {
  168.                 goto FailurePoint2;
  169.             }
  170.  
  171.         /* 24..27 */
  172.         /*     "COMM" */
  173.         if (!WriteBufferedOutput(Output,4,"COMM"))
  174.             {
  175.                 goto FailurePoint2;
  176.             }
  177.  
  178.         /* 28..31 */
  179.         /*     4-byte big endian length. */
  180.         /*        22 + compression method string length for AIFF-C files */
  181.         if (!WriteBufferedUnsignedLongBigEndian(Output,38))
  182.             {
  183.                 goto FailurePoint2;
  184.             }
  185.  
  186.         /* 32..33 */
  187.         /*     2-byte big endian number of channels */
  188.         if (Info->UseStereo)
  189.             {
  190.                 if (!WriteBufferedUnsignedShortBigEndian(Output,2))
  191.                     {
  192.                         goto FailurePoint2;
  193.                     }
  194.             }
  195.          else
  196.             {
  197.                 if (!WriteBufferedUnsignedShortBigEndian(Output,1))
  198.                     {
  199.                         goto FailurePoint2;
  200.                     }
  201.             }
  202.  
  203.         /* 34..37 */
  204.         /*     4-byte big endian number of sample frames */
  205.         if (!WriteBufferedUnsignedLongBigEndian(Output,0)) /* RESOLVED LATER */
  206.             {
  207.                 goto FailurePoint2;
  208.             }
  209.  
  210.         /* 38..39 */
  211.         /*     2-byte big endian number of bits per sample */
  212.         /*        a value in the domain 1..32 */
  213.         switch (Info->NumBitsOut)
  214.             {
  215.                 default:
  216.                     EXECUTE(PRERR(ForceAbort,"SetUpAIFFHeader:  bad number of bits"));
  217.                     break;
  218.                 case eOutput8Bits:
  219.                     if (!WriteBufferedUnsignedShortBigEndian(Output,8))
  220.                         {
  221.                             goto FailurePoint2;
  222.                         }
  223.                     break;
  224.                 case eOutput16Bits:
  225.                     if (!WriteBufferedUnsignedShortBigEndian(Output,16))
  226.                         {
  227.                             goto FailurePoint2;
  228.                         }
  229.                     break;
  230.                 case eOutput24Bits:
  231.                     if (!WriteBufferedUnsignedShortBigEndian(Output,24))
  232.                         {
  233.                             goto FailurePoint2;
  234.                         }
  235.                     break;
  236.                 case eOutput32Bits:
  237.                     if (!WriteBufferedUnsignedShortBigEndian(Output,32))
  238.                         {
  239.                             goto FailurePoint2;
  240.                         }
  241.                     break;
  242.             }
  243.  
  244.         /* 40..49 */
  245.         /*     10-byte extended precision number of frames per second */
  246.         /* extended 22050 = 400D AC44000000000000 */
  247.         /* extended 22051 = 400D AC46000000000000 */
  248.         /* extended 44100 = 400E AC44000000000000 */
  249.         /* extended 44101 = 400E AC45000000000000 */
  250.         Exponent = 0x401e;
  251.         Mantissa = Info->SamplingRate;
  252.         while ((Mantissa & 0x80000000) == 0)
  253.             {
  254.                 Mantissa = Mantissa << 1;
  255.                 Exponent -= 1;
  256.             }
  257.         StupidExtendedThing[0] = (Exponent >> 8) & 0xff;
  258.         StupidExtendedThing[1] = Exponent & 0xff;
  259.         StupidExtendedThing[2] = (Mantissa >> 24) & 0xff;
  260.         StupidExtendedThing[3] = (Mantissa >> 16) & 0xff;
  261.         StupidExtendedThing[4] = (Mantissa >> 8) & 0xff;
  262.         StupidExtendedThing[5] = Mantissa & 0xff;
  263.         StupidExtendedThing[6] = 0;
  264.         StupidExtendedThing[7] = 0;
  265.         StupidExtendedThing[8] = 0;
  266.         StupidExtendedThing[9] = 0;
  267.         if (!WriteBufferedOutput(Output,10,StupidExtendedThing))
  268.             {
  269.                 goto FailurePoint2;
  270.             }
  271.  
  272.         /* 50..53 */
  273.         /*     4-byte character code ID for the compression method */
  274.         /*        "NONE" means there is no compression method used */
  275.         if (!WriteBufferedOutput(Output,4,"NONE"))
  276.             {
  277.                 goto FailurePoint2;
  278.             }
  279.  
  280.         /* 54..69 */
  281.         /*     some characters in a string identifying the compression method */
  282.         /*        this must be padded to an even number of bytes, but the pad is */
  283.         /*        NOT included in the length descriptor for the chunk. */
  284.         /*        for uncompressed data, the string should be */
  285.         /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  286.         /*        the total chunk length is thus 38 bytes. */
  287.         if (!WriteBufferedOutput(Output,16,"\x0enot compressed\x00"))
  288.             {
  289.                 goto FailurePoint2;
  290.             }
  291.  
  292.         /* 70..73 */
  293.         /*     "SSND" */
  294.         if (!WriteBufferedOutput(Output,4,"SSND"))
  295.             {
  296.                 goto FailurePoint2;
  297.             }
  298.  
  299.         /* 74..77 */
  300.         /*     4-byte big endian number of bytes in sample data array */
  301.         if (!WriteBufferedUnsignedLongBigEndian(Output,0)) /* RESOLVED LATER */
  302.             {
  303.                 goto FailurePoint2;
  304.             }
  305.  
  306.         /* 78..81 */
  307.         /*     4-byte big endian offset to the first byte of sample data in the array */
  308.         if (!WriteBufferedUnsignedLongBigEndian(Output,0))
  309.             {
  310.                 goto FailurePoint2;
  311.             }
  312.  
  313.         /* 82..85 */
  314.         /*     4-byte big endian number of bytes to which the sound data is aligned. */
  315.         if (!WriteBufferedUnsignedLongBigEndian(Output,0))
  316.             {
  317.                 goto FailurePoint2;
  318.             }
  319.  
  320.         /*     any length vector of raw sound data. */
  321.         /*        this must be padded to an even number of bytes, but the pad is */
  322.         /*        NOT included in the length descriptor for the chunk. */
  323.         /*        Samples are stored in an integral number of bytes, the smallest that */
  324.         /*        is required for the specified number of bits.  If this is not an even */
  325.         /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  326.         /*        Multichannel sound is interleaved with the left channel first. */
  327.  
  328.         if (!EndBufferedOutput(Output))
  329.             {
  330.                 return False;
  331.             }
  332.  
  333.         return True;
  334.     }
  335.  
  336.  
  337. /* update various size fields in the file */
  338. static MyBoolean            ResolveAIFFHeader(FileType* OutputFile, StateRecord* Info)
  339.     {
  340.         long                                TotalBytesOfSamples;
  341.         MyBoolean                        FileSuccess;
  342.         char                                Buffer[4];
  343.  
  344.         TotalBytesOfSamples = Info->TotalSampleCount;
  345.         if (Info->UseStereo)
  346.             {
  347.                 TotalBytesOfSamples *= 2;
  348.             }
  349.         switch (Info->NumBitsOut)
  350.             {
  351.                 default:
  352.                     EXECUTE(PRERR(ForceAbort,"ResolveAIFFHeader:  bad number of bits"));
  353.                     break;
  354.                 case eOutput8Bits:
  355.                     break;
  356.                 case eOutput16Bits:
  357.                     TotalBytesOfSamples *= 2;
  358.                     break;
  359.                 case eOutput24Bits:
  360.                     TotalBytesOfSamples *= 3;
  361.                     break;
  362.                 case eOutput32Bits:
  363.                     TotalBytesOfSamples *= 4;
  364.                     break;
  365.             }
  366.  
  367.         FileSuccess = True;
  368.  
  369.         /* make sure file is an even number of bytes */
  370.         if ((GetFilePosition(OutputFile) & 1) != 0)
  371.             {
  372.                 char                        Stupid[1] = {0};
  373.  
  374.                 if (0 != WriteToFile(OutputFile,Stupid,1))
  375.                     {
  376.                         FileSuccess = False;
  377.                     }
  378.             }
  379.  
  380.         /* chop off any crud from the end */
  381.         FileSuccess = SetFileLength(OutputFile,GetFilePosition(OutputFile)) && FileSuccess;
  382.  
  383.         /* 4..7 */
  384.         /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  385.         if (SetFilePosition(OutputFile,4))
  386.             {
  387.                 Buffer[0] = ((TotalBytesOfSamples + 78 - 8) >> 24) & 0xff;
  388.                 Buffer[1] = ((TotalBytesOfSamples + 78 - 8) >> 16) & 0xff;
  389.                 Buffer[2] = ((TotalBytesOfSamples + 78 - 8) >> 8) & 0xff;
  390.                 Buffer[3] = (TotalBytesOfSamples + 78 - 8) & 0xff;
  391.                 if (0 != WriteToFile(OutputFile,Buffer,4))
  392.                     {
  393.                         FileSuccess = False;
  394.                     }
  395.             }
  396.          else
  397.             {
  398.                 FileSuccess = False;
  399.             }
  400.  
  401.         /* 34..37 */
  402.         /*     4-byte big endian number of sample frames */
  403.         if (SetFilePosition(OutputFile,34))
  404.             {
  405.                 Buffer[0] = (Info->TotalSampleCount >> 24) & 0xff;
  406.                 Buffer[1] = (Info->TotalSampleCount >> 16) & 0xff;
  407.                 Buffer[2] = (Info->TotalSampleCount >> 8) & 0xff;
  408.                 Buffer[3] = Info->TotalSampleCount & 0xff;
  409.                 if (0 != WriteToFile(OutputFile,Buffer,4))
  410.                     {
  411.                         FileSuccess = False;
  412.                     }
  413.             }
  414.          else
  415.             {
  416.                 FileSuccess = False;
  417.             }
  418.  
  419.         /* 74..77 */
  420.         /*     4-byte big endian number of bytes in sample data array */
  421.         if (SetFilePosition(OutputFile,74))
  422.             {
  423.                 Buffer[0] = (TotalBytesOfSamples >> 24) & 0xff;
  424.                 Buffer[1] = (TotalBytesOfSamples >> 16) & 0xff;
  425.                 Buffer[2] = (TotalBytesOfSamples >> 8) & 0xff;
  426.                 Buffer[3] = TotalBytesOfSamples & 0xff;
  427.                 if (0 != WriteToFile(OutputFile,Buffer,4))
  428.                     {
  429.                         FileSuccess = False;
  430.                     }
  431.             }
  432.          else
  433.             {
  434.                 FileSuccess = False;
  435.             }
  436.  
  437.         return FileSuccess;
  438.     }
  439.  
  440.  
  441. static MyBoolean            CallbackRoutine(StateRecord* Info, largefixedsigned* DataBlock,
  442.                                                 long NumFrames, MyBoolean* AbortPlaybackFlagOut)
  443.     {
  444.         long                                Limit;
  445.         void*                                Buffer;
  446.         long                                BufferSizeInBytes;
  447.         char*                                DataOutThing;
  448.         long                                DataOutInBytes;
  449.         long                                Scan;
  450.         largefixedsigned        TempValue;
  451.         long                                UnwritableBytes;
  452.  
  453.         Info->CancelCheck -= 1;
  454.         if (Info->CancelCheck < 0)
  455.             {
  456.                 Info->CancelCheck = CANCELCHECKTIMER;
  457.                 if (RelinquishCPUJudiciouslyCheckCancel())
  458.                     {
  459.                         switch (AskYesNoCancel("Are you sure you want to abort synthesis?",NIL,
  460.                             "Abort","Resume",NIL))
  461.                             {
  462.                                 default:
  463.                                     EXECUTE(PRERR(ForceAbort,"DiskFileOutput:CallbackRoutine:  bad value "
  464.                                         "from AskYesNoCancel"));
  465.                                     break;
  466.                                 case eYes:
  467.                                     *AbortPlaybackFlagOut = True;
  468.                                     return True;
  469.                                 case eNo:
  470.                                     break;
  471.                             }
  472.                         /* at first glance, we might need to somehow reset the RelinquishCPU */
  473.                         /* sticky cancel flag, but AskYesNoCancel calls the event loop, so */
  474.                         /* it gets automatically reset. */
  475.                     }
  476.             }
  477.  
  478.         /* calculate required buffer size */
  479.         Limit = NumFrames;
  480.         BufferSizeInBytes = NumFrames;
  481.         DataOutInBytes = NumFrames;
  482.         if (Info->UseStereo)
  483.             {
  484.                 Limit *= 2; /* twice as many frames for stereo */
  485.                 BufferSizeInBytes *= 2;
  486.                 DataOutInBytes *= 2;
  487.             }
  488.         switch (Info->NumBitsOut)
  489.             {
  490.                 default:
  491.                     EXECUTE(PRERR(ForceAbort,"CallbackRoutine:  bad number of bits"));
  492.                     break;
  493.                 case eOutput8Bits:
  494.                     break;
  495.                 case eOutput16Bits:
  496.                     BufferSizeInBytes *= sizeof(short);
  497.                     DataOutInBytes *= 2;
  498.                     break;
  499.                 case eOutput24Bits:
  500.                     BufferSizeInBytes *= sizeof(largefixedsigned);
  501.                     DataOutInBytes *= 3;
  502.                     break;
  503.                 case eOutput32Bits:
  504.                     BufferSizeInBytes *= sizeof(largefixedsigned);
  505.                     DataOutInBytes *= 4;
  506.                     break;
  507.             }
  508.         Buffer = AllocPtrCanFail(BufferSizeInBytes,"AudioFileOutputBuffer");
  509.         if (Buffer == NIL)
  510.             {
  511.              FailurePoint1:
  512.                 AlertHalt("There is not enough memory available to continue synthesis.",NIL);
  513.                 return False;
  514.             }
  515.         DataOutThing = AllocPtrCanFail(DataOutInBytes,"AudioFileOutputBuffer2");
  516.         if (DataOutThing == NIL)
  517.             {
  518.              FailurePoint2:
  519.                 ReleasePtr(DataOutThing);
  520.                 goto FailurePoint1;
  521.             }
  522.  
  523.         /* generate the data into the buffer */
  524.         switch (Info->NumBitsOut)
  525.             {
  526.                 default:
  527.                     EXECUTE(PRERR(ForceAbort,"SynthToAIFFFile:  bad number of bits"));
  528.                     break;
  529.                 case eOutput8Bits:
  530.                     for (Scan = 0; Scan < Limit; Scan += 1)
  531.                         {
  532.                             PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  533.                             TempValue = DataBlock[Scan] + double2largefixed((double)1 / 65536);
  534.                             if (TempValue > int2largefixed(1) - 1)
  535.                                 {
  536.                                     Info->ClippedSampleCount += 1;
  537.                                     if (TempValue > Info->MaxClipExtent)
  538.                                         {
  539.                                             Info->MaxClipExtent = TempValue;
  540.                                         }
  541.                                     TempValue = int2largefixed(1) - 1;
  542.                                 }
  543.                             else if (TempValue < - (int2largefixed(1) - 1))
  544.                                 {
  545.                                     Info->ClippedSampleCount += 1;
  546.                                     if (- TempValue > Info->MaxClipExtent)
  547.                                         {
  548.                                             Info->MaxClipExtent = - TempValue;
  549.                                         }
  550.                                     TempValue = - (int2largefixed(1) - 1);
  551.                                 }
  552.                             PRNGCHK(Buffer,&(((signed char*)Buffer)[Scan]),
  553.                                 sizeof(((signed char*)Buffer)[Scan]));
  554.                             ((signed char*)Buffer)[Scan] = TempValue >> (largefixed_precision - 8 + 1);
  555.                         }
  556.                     break;
  557.                 case eOutput16Bits:
  558.                     for (Scan = 0; Scan < Limit; Scan += 1)
  559.                         {
  560.                             PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  561.                             TempValue = DataBlock[Scan] + double2largefixed((double)1 / 65536);
  562.                             if (TempValue > int2largefixed(1) - 1)
  563.                                 {
  564.                                     Info->ClippedSampleCount += 1;
  565.                                     if (TempValue > Info->MaxClipExtent)
  566.                                         {
  567.                                             Info->MaxClipExtent = TempValue;
  568.                                         }
  569.                                     TempValue = int2largefixed(1) - 1;
  570.                                 }
  571.                             else if (TempValue < - (int2largefixed(1) - 1))
  572.                                 {
  573.                                     Info->ClippedSampleCount += 1;
  574.                                     if (- TempValue > Info->MaxClipExtent)
  575.                                         {
  576.                                             Info->MaxClipExtent = - TempValue;
  577.                                         }
  578.                                     TempValue = - (int2largefixed(1) - 1);
  579.                                 }
  580.                             PRNGCHK(Buffer,&(((signed short*)Buffer)[Scan]),
  581.                                 sizeof(((signed short*)Buffer)[Scan]));
  582.                             ((signed short*)Buffer)[Scan] = TempValue >> (largefixed_precision - 16 + 1);
  583.                         }
  584.                     break;
  585.                 case eOutput24Bits:
  586.                     for (Scan = 0; Scan < Limit; Scan += 1)
  587.                         {
  588.                             PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  589.                             TempValue = DataBlock[Scan];
  590.                             if (TempValue > int2largefixed(1) - 1)
  591.                                 {
  592.                                     Info->ClippedSampleCount += 1;
  593.                                     if (TempValue > Info->MaxClipExtent)
  594.                                         {
  595.                                             Info->MaxClipExtent = TempValue;
  596.                                         }
  597.                                     TempValue = int2largefixed(1) - 1;
  598.                                 }
  599.                             else if (TempValue < - (int2largefixed(1) - 1))
  600.                                 {
  601.                                     Info->ClippedSampleCount += 1;
  602.                                     if (- TempValue > Info->MaxClipExtent)
  603.                                         {
  604.                                             Info->MaxClipExtent = - TempValue;
  605.                                         }
  606.                                     TempValue = - (int2largefixed(1) - 1);
  607.                                 }
  608.                             PRNGCHK(Buffer,&(((signed short*)Buffer)[Scan]),
  609.                                 sizeof(((signed short*)Buffer)[Scan]));
  610.                             ((largefixedsigned*)Buffer)[Scan] = TempValue >> (largefixed_precision - 24 + 1);
  611.                         }
  612.                     break;
  613.                 case eOutput32Bits:
  614.                     /* 32-bits doesn't clip. */
  615.                     for (Scan = 0; Scan < Limit; Scan += 1)
  616.                         {
  617.                             PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  618.                             TempValue = DataBlock[Scan];
  619.                             PRNGCHK(Buffer,&(((signed short*)Buffer)[Scan]),
  620.                                 sizeof(((signed short*)Buffer)[Scan]));
  621.                             ((largefixedsigned*)Buffer)[Scan] = TempValue;
  622.                         }
  623.                     break;
  624.             }
  625.  
  626.         /* reorder the data to be big-endian */
  627.         switch (Info->NumBitsOut)
  628.             {
  629.                 default:
  630.                     EXECUTE(PRERR(ForceAbort,"SynthToAIFFFile:  bad number of bits"));
  631.                     break;
  632.                 case eOutput8Bits:
  633.                     for (Scan = 0; Scan < Limit; Scan += 1)
  634.                         {
  635.                             signed short                TempVal;
  636.  
  637.                             PRNGCHK(Buffer,&(((signed char*)Buffer)[Scan]),
  638.                                 sizeof(((signed char*)Buffer)[Scan]));
  639.                             TempVal = ((signed char*)Buffer)[Scan];
  640.                             PRNGCHK(DataOutThing,&(DataOutThing[Scan]),sizeof(DataOutThing[Scan]));
  641.                             DataOutThing[Scan] = TempVal;
  642.                         }
  643.                     break;
  644.                 case eOutput16Bits:
  645.                     for (Scan = 0; Scan < Limit; Scan += 1)
  646.                         {
  647.                             signed short                TempVal;
  648.  
  649.                             PRNGCHK(Buffer,&(((signed short*)Buffer)[Scan]),
  650.                                 sizeof(((signed short*)Buffer)[Scan]));
  651.                             TempVal = ((signed short*)Buffer)[Scan];
  652.                             PRNGCHK(DataOutThing,&(DataOutThing[2 * Scan + 0]),
  653.                                 sizeof(DataOutThing[2 * Scan + 0]) * 2);
  654.                             DataOutThing[2 * Scan + 1] = TempVal & 0xff;
  655.                             DataOutThing[2 * Scan + 0] = (TempVal >> 8) & 0xff;
  656.                         }
  657.                     break;
  658.                 case eOutput24Bits:
  659.                     for (Scan = 0; Scan < Limit; Scan += 1)
  660.                         {
  661.                             largefixedsigned        TempVal;
  662.  
  663.                             PRNGCHK(Buffer,&(((largefixedsigned*)Buffer)[Scan]),
  664.                                 sizeof(((largefixedsigned*)Buffer)[Scan]));
  665.                             TempVal = ((largefixedsigned*)Buffer)[Scan];
  666.                             PRNGCHK(DataOutThing,&(DataOutThing[3 * Scan + 0]),
  667.                                 sizeof(DataOutThing[3 * Scan + 0]) * 3);
  668.                             DataOutThing[3 * Scan + 2] = TempVal & 0xff;
  669.                             DataOutThing[3 * Scan + 1] = (TempVal >> 8) & 0xff;
  670.                             DataOutThing[3 * Scan + 0] = (TempVal >> 16) & 0xff;
  671.                         }
  672.                     break;
  673.                 case eOutput32Bits:
  674.                     for (Scan = 0; Scan < Limit; Scan += 1)
  675.                         {
  676.                             largefixedsigned        TempVal;
  677.  
  678.                             PRNGCHK(Buffer,&(((largefixedsigned*)Buffer)[Scan]),
  679.                                 sizeof(((largefixedsigned*)Buffer)[Scan]));
  680.                             TempVal = ((largefixedsigned*)Buffer)[Scan];
  681.                             PRNGCHK(DataOutThing,&(DataOutThing[4 * Scan + 0]),
  682.                                 sizeof(DataOutThing[4 * Scan + 0]) * 4);
  683.                             DataOutThing[4 * Scan + 3] = TempVal & 0xff;
  684.                             DataOutThing[4 * Scan + 2] = (TempVal >> 8) & 0xff;
  685.                             DataOutThing[4 * Scan + 1] = (TempVal >> 16) & 0xff;
  686.                             DataOutThing[4 * Scan + 0] = (TempVal >> 24) & 0xff;
  687.                         }
  688.                     break;
  689.             }
  690.  
  691.         /* write data to the file */
  692.      RetryPoint:
  693.         UnwritableBytes = WriteToFile(Info->OutputFile,DataOutThing,DataOutInBytes);
  694.         if (UnwritableBytes != 0)
  695.             {
  696.                 switch (AskYesNoCancel("An error occurred writing to the file.  The disk "
  697.                     "may be full.  Do you want to try writing again?",NIL,"Retry","Abort",NIL))
  698.                     {
  699.                         default:
  700.                             EXECUTE(PRERR(ForceAbort,"SynthToAIFFFile:  bad value from AskYesNoCancel"));
  701.                             break;
  702.                         case eYes:
  703.                             /* back up */
  704.                             if (!SetFilePosition(Info->OutputFile,GetFilePosition(Info->OutputFile)
  705.                                 - (UnwritableBytes - DataOutInBytes)))
  706.                                 {
  707.                                     AlertHalt("File position could not be reset.  Aborting synthesis.",NIL);
  708.                                  FailurePoint3:
  709.                                     ReleasePtr(DataOutThing);
  710.                                     goto FailurePoint2;
  711.                                     return False;
  712.                                 }
  713.                             goto RetryPoint;
  714.                         case eNo:
  715.                             /* clean up */
  716.                             SetFilePosition(Info->OutputFile,GetFilePosition(Info->OutputFile)
  717.                                 - (UnwritableBytes - DataOutInBytes));
  718.                             goto FailurePoint3;
  719.                     }
  720.             }
  721.  
  722.         Info->TotalSampleCount += NumFrames;
  723.  
  724.         UpdateSynthWindow(Info->Window,Info->SamplingRate,Info->TotalSampleCount,
  725.             Info->ClippedSampleCount,False);
  726.  
  727.         ReleasePtr((char*)Buffer);
  728.         ReleasePtr(DataOutThing);
  729.  
  730.         return True;
  731.     }
  732.  
  733.  
  734. /* this routine opens a file and dumps the data to it. */
  735. void                                    SynthToAIFFFile(struct MainWindowRec* MainWindow,
  736.                                                 struct ArrayRec* ListOfTracks, struct TrackObjectRec* KeyTrack,
  737.                                                 long FrameToStartAt, long SamplingRate, long EnvelopeRate,
  738.                                                 MyBoolean UseStereo, LargeBCDType DefaultBeatsPerMinute,
  739.                                                 LargeBCDType OverallVolumeScalingReciprocal,
  740.                                                 MyBoolean InterpOverTime, MyBoolean InterpAcrossWaves,
  741.                                                 LargeBCDType ScanningGap, OutputNumBitsType NumBitsOut,
  742.                                                 MyBoolean ClipWarn)
  743.     {
  744.         StateRecord                    StateInfo;
  745.         SynthErrorCodes            SynthErrorReturnCode;
  746.         FileSpec*                        WhereToSaveFile;
  747.         ErrorDaemonRec*            ErrorDaemon;
  748.  
  749.         CheckPtrExistence(MainWindow);
  750.         CheckPtrExistence(ListOfTracks);
  751.         CheckPtrExistence(KeyTrack);
  752.  
  753.         StateInfo.UseStereo = UseStereo;
  754.         StateInfo.SamplingRate = SamplingRate;
  755.         StateInfo.NumBitsOut = NumBitsOut;
  756.  
  757.         StateInfo.TotalSampleCount = 0;
  758.         StateInfo.ClippedSampleCount = 0;
  759.         StateInfo.MaxClipExtent = 0;
  760.  
  761.         StateInfo.CancelCheck = 0;
  762.  
  763.         StateInfo.Window = NewSynthWindow(EnvelopeRate / 2,True/*show clipping*/);
  764.         if (StateInfo.Window == NIL)
  765.             {
  766.                 AlertHalt("There is not enough memory available to perform synthesis.",NIL);
  767.              SetupFailurePoint1:
  768.                 return;
  769.             }
  770.  
  771.         WhereToSaveFile = PutFile("AIFF Output File");
  772.         if (WhereToSaveFile == NIL)
  773.             {
  774.              SetupFailurePoint2:
  775.                 DisposeSynthWindow(StateInfo.Window);
  776.                 goto SetupFailurePoint1;
  777.             }
  778.  
  779.         if (!CreateFile(WhereToSaveFile,ApplicationCreator,CODE4BYTES('A','I','F','F')))
  780.             {
  781.                 AlertHalt("Unable to create the file.",NIL);
  782.              SetupFailurePoint3:
  783.                 DisposeFileSpec(WhereToSaveFile);
  784.                 goto SetupFailurePoint2;
  785.             }
  786.  
  787.         if (!OpenFile(WhereToSaveFile,&(StateInfo.OutputFile),eReadAndWrite))
  788.             {
  789.                 AlertHalt("Unable to open the file for writing.",NIL);
  790.              SetupFailurePoint4:
  791.                 goto SetupFailurePoint3;
  792.             }
  793.  
  794.         if (!SetUpAIFFHeader(StateInfo.OutputFile,&StateInfo))
  795.             {
  796.                 AlertHalt("Unable to write data to the file.",NIL);
  797.              SetupFailurePoint5:
  798.                 CloseFile(StateInfo.OutputFile);
  799.                 goto SetupFailurePoint4;
  800.             }
  801.  
  802.         ErrorDaemon = NewErrorDaemon();
  803.         if (ErrorDaemon == NIL)
  804.             {
  805.                 AlertHalt("There is not enough memory available to perform synthesis.",NIL);
  806.              SetupFailurePoint6:
  807.                 goto SetupFailurePoint5;
  808.             }
  809.  
  810.         SynthErrorReturnCode = Synthesizer(MainWindow,
  811.             (MyBoolean (*)(void*,largefixedsigned*,long,MyBoolean*))&CallbackRoutine,
  812.             &StateInfo,ListOfTracks,KeyTrack,FrameToStartAt,SamplingRate,EnvelopeRate,
  813.             UseStereo,DefaultBeatsPerMinute,OverallVolumeScalingReciprocal,InterpOverTime,
  814.             InterpAcrossWaves,ScanningGap,ErrorDaemon);
  815.  
  816.         UpdateSynthWindow(StateInfo.Window,StateInfo.SamplingRate,StateInfo.TotalSampleCount,
  817.             StateInfo.ClippedSampleCount,True);
  818.  
  819.         if (!ResolveAIFFHeader(StateInfo.OutputFile,&StateInfo))
  820.             {
  821.                 AlertHalt("Unable to properly finalize the data in the file.  It will "
  822.                     "probably be unusable without manual repair.",NIL);
  823.             }
  824.  
  825.         switch (SynthErrorReturnCode)
  826.             {
  827.                 default:
  828.                     EXECUTE(PRERR(AllowResume,
  829.                         "SynthToSoundDevice:  bad return code from Synthesizer()"));
  830.                     break;
  831.                 case eSynthDone:
  832.                     break;
  833.                 case eSynthNoMemory:
  834.                     AlertHalt("There is not enough memory available to continue synthesis.",NIL);
  835.                     break;
  836.                 case eSynthUserCancelled:
  837.                     break;
  838.                 /* case eSynthProgramError: */
  839.                     break;
  840.                 case eSynthPrereqError:
  841.                     break;
  842.                 case eSynthUndefinedInstrumentError:
  843.                     break;
  844.                 case eSynthDataSubmitError:
  845.                     break;
  846.                 case eSynthDuplicateNames:
  847.                     break;
  848.             }
  849.  
  850.         CloseFile(StateInfo.OutputFile);
  851.         DisposeFileSpec(WhereToSaveFile);
  852.         DisposeSynthWindow(StateInfo.Window);
  853.  
  854.         if (ErrorDaemonDidClampingOccur(ErrorDaemon))
  855.             {
  856.                 ClampWarnDialog(ErrorDaemonGetMaxClamping(ErrorDaemon),
  857.                     ErrorDaemonGetMaxClamping(ErrorDaemon)
  858.                     * LargeBCD2Double(OverallVolumeScalingReciprocal));
  859.             }
  860.          else
  861.             {
  862.                 if (ClipWarn && (StateInfo.ClippedSampleCount != 0))
  863.                     {
  864.                         ClipWarnDialog(StateInfo.ClippedSampleCount,StateInfo.TotalSampleCount,
  865.                             largefixed2double(StateInfo.MaxClipExtent),
  866.                             largefixed2double(StateInfo.MaxClipExtent)
  867.                             * LargeBCD2Double(OverallVolumeScalingReciprocal),False);
  868.                     }
  869.             }
  870.  
  871.         DisposeErrorDaemon(ErrorDaemon);
  872.     }
  873.